<template>
  <div
    :class="[prefixCls]"
    @mouseenter="handleShowPopper"
    @mouseleave="handleClosePopper"
  >
    <div :class="[prefixCls + '-rel']" ref="reference">
      <slot></slot>
    </div>
    <teleport to="body" :disabled="!transfer">
      <transition name="fade">
        <div
          ref="popper"
          v-show="!disabled && (visible || always)"
          :class="dropdownCls"
          :style="dropStyles"
          @mouseenter="handleShowPopper"
          @mouseleave="handleClosePopper"
        >
          <div
            :class="[prefixCls + '-arrow']"
            v-if="visibleArrow"
            data-popper-arrow
            ref="arrow"
          ></div>
          <div :class="[prefixCls + '-content']">
            <div :class="innerClasses" :style="innerStyles">
              <slot name="content">{{ content }}</slot>
            </div>
          </div>
        </div>
      </transition>
    </teleport>
  </div>
</template>
<script setup>
import {
  getCurrentInstance,
  nextTick,
  ref,
  unref,
  watch,
  computed,
  onUpdated,
  onBeforeUnmount,
  onMounted,
} from 'vue'
import { oneOf } from '../../utils/assist'
import { transferIndex, transferIncrease } from './useUtils'

import { createPopper } from '@popperjs/core'

const prefixCls = ref('haloe-tooltip')

const props = defineProps({
  placement: {
    validator(value) {
      return oneOf(value, [
        'top',
        'top-start',
        'top-end',
        'bottom',
        'bottom-start',
        'bottom-end',
        'left',
        'left-start',
        'left-end',
        'right',
        'right-start',
        'right-end',
      ])
    },
    default: 'bottom',
  },
  content: {
    type: [String, Number],
    default: '',
  },
  delay: {
    type: Number,
    default: 100,
  },
  disappear: {
    type: Number,
    default: 100,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  controlled: {
    // under this prop,Tooltip will not close when mouseleave
    type: Boolean,
    default: false,
  },
  always: {
    type: Boolean,
    default: false,
  },
  transfer: {
    type: Boolean,
    default() {
      const global = getCurrentInstance().appContext.config.globalProperties
      return !global.$HALOE || global.$HALOE.transfer === ''
        ? false
        : global.$HALOE.transfer
    },
  },
  theme: {
    validator(value) {
      return oneOf(value, ['dark', 'light'])
    },
    default: 'dark',
  },
  maxWidth: {
    type: [String, Number],
  },
  transferClassName: {
    type: String,
  },
  // eventsEnabled: {
  //   type: Boolean,
  //   default: false,
  // },
  boundariesPadding: {
    type: Number,
    default: 5,
  },
  offset: {
    type: Number,
    // default:8,
    // default: [0, 10],
  },
  modelValue: {
    type: Boolean,
    default: false,
  },
  transition: String,
  visibleArrow: {
    type: Boolean,
    default: true
  }
})

const emits = defineEmits([
  'on-popper-show',
  'on-popper-hide',
  'created',
  'update:modelValue',
])


const popper = ref()
const reference = ref()
const arrow = ref()
let visible = ref(props.modelValue)
let timeout = ref()
const popperJS = ref()
let tIndex = ref()

const handleGetIndex = () => {
  transferIncrease()
  return transferIndex
}

tIndex.value=handleGetIndex()

const handleShowPopper = () => {
  if (timeout.value) clearTimeout(timeout.value)
  timeout.value = setTimeout(() => {
    visible.value = true
  }, props.delay)
  tIndex.value = handleGetIndex()
}

const handleClosePopper = () => {
  if (timeout.value) {
    clearTimeout(timeout.value)
    if (!props.controlled) {
      timeout.value = setTimeout(() => {
        visible.value = false
      }, props.disappear)
    }
  }
}

const updatePopper = () => {
  // if (isServer) return;
  popperJS.value ? popperJS.value.update() : createRefPopper()
}

const createRefPopper = () => {
  if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(props.placement)) {
    return
  }

  if (!popper.value || !reference.value) return

  if (unref(popperJS) && unref(popperJS).hasOwnProperty('destroy')) {
    unref(popperJS).destroy()
  }
  popperJS.value = new createPopper(reference.value, popper.value, {
    placement: props.placement,
    modifiers: [
      {
        name: 'offset',
        options: {
          offset: [0, props.offset?props.offset:8],
        },
      },
      {
        name: 'preventOverflow',
        options: {
          padding: {
            top: 2,
            bottom: 2,
            left: 5,
            right: 5,
          },
        },
      },
      {
        name: 'arrow',
        options: {
          element: arrow.value,
          padding: 4,
        },
      },
      {
        name: 'flip',
        options: {
          padding: 0,
          // fallbackPlacements,
        },
      },
      {
        name: 'computeStyles',
        options: {
          gpuAcceleration: false,
        },
      },
      // { name: 'eventListeners', enabled: this.eventsEnabled },
    ],
    onFirstUpdate: (state) => {
      nextTick(updatePopper)
      // this.$emit('created', this)
      emits('created', getCurrentInstance())
    },
  })

}

const innerStyles = computed(() => {
  const styles = {}
  if (props.maxWidth) styles['max-width'] = `${props.maxWidth}px`
  return styles
})


const innerClasses = computed(() => {
  return [
    `${unref(prefixCls)}-inner`,
    {
      [`${unref(prefixCls)}-inner-with-width`]: !!props.maxWidth,
    },
  ]
})

const dropStyles = computed(() => {
  let styles = {}
  if (props.transfer) styles['z-index'] = 1060 + unref(tIndex)

  return styles
})
const dropdownCls = computed(() => {
  return [
    `${unref(prefixCls)}-popper`,
    `${unref(prefixCls)}-${props.theme}`,
    {
      [unref(prefixCls) + '-transfer']: props.transfer,
      [props.transferClassName]: props.transferClassName,
    },
  ]
})

watch(
  () => props.content,
  () => {
    updatePopper()
  }
)

watch(
  () => props.modelValue,
  (val) => {
    visible.value = val
    emits('update:modelValue', val)
  },{
    immediate:true
  }
)
watch(
  () => visible.value,
  (val) => {
    if (val) {
      // this.$refs.popper.setAttribute('data-show', '')
      // setTimeout(()=>{
      //   popper.value.setAttribute('data-show', '')
      // } ,100)
      // popper.value.setAttribute('data-show', '')
      // console.log("popper",popper.value)
      updatePopper()
      emits('on-popper-show')
    } else {
      // popper.value.removeAttribute('data-show', '')
      emits('on-popper-hide')
    }
    emits('update:modelValue', val)
  }
)


onUpdated(() => {
  nextTick(() => updatePopper())
})

onBeforeUnmount(() => {
  if (popperJS.value) {
    popperJS.value.destroy()
  }
})

onMounted(() => {
  if (props.always) {
    updatePopper()
  }
})

defineExpose({
  updatePopper
})

</script>
